//
//  Base16.m
//  App
//
//  Created by gome on 2018/11/29.
//  Copyright © 2018 gome. All rights reserved.
//

#import "Base16.h"
static const char *defaultBaseList = "0123456789ABCabc";

@implementation Base16
/**
 base16 加密

 @param originString 被加密字符串
 @param keyList 加密key
 @return 加密后的字符串
 */
+ (NSString *)enCodeBase16String:(NSString *)originString keyList:(NSString *)keyList {
    
    if (!originString) {
        return nil;
    }
    
    const char *myKeyList = defaultBaseList;
    if (keyList) {
        NSString *keyString = keyList;
        myKeyList = [keyString UTF8String];
    }
    
    const char *bytes = [originString UTF8String];
    long originSize = strlen(bytes);
    
    long baseSize = 2 * strlen(bytes) + 1;
    char base16Char[baseSize];
    
    encodeBase16(bytes, originSize, myKeyList, base16Char);
    NSString *base16String = [NSString stringWithCString:base16Char encoding:NSASCIIStringEncoding];
    
    return base16String;
}



/**
 base16 解密

 @param base16String 解密字符串
 @param keyList 解密key
 @return 解密后的字符串
 */
+ (NSString *)deCodeBase16String:(NSString *)base16String keyList:(NSString *)keyList {
    
    if (!base16String) {
        return nil;
    }
    
    const char *myKeyList = defaultBaseList;
    if (keyList) {
        NSString *keyString = keyList;
        myKeyList = [keyString UTF8String];
    }

    const char *base16Char = [base16String UTF8String];
    
    long base16Size = strlen(base16Char);
    char originChar[base16Size];

    decodeBase16(base16Char, base16Size, myKeyList, originChar);
    NSString *originString = [NSString stringWithCString:originChar encoding:NSASCIIStringEncoding];
    
    return originString;

}

/**
 base16加密 （单调双返回） 取出原始字符串中的一个字符，把字符分为两段，每段长4bit，对应的二进制数作为base数组的下标取出对应的字符赋值给编码后的字符串对应的位

 @param buf 加密的字符串
 @param size 加密字符串长度
 @param baseCharList 加密key
 @param base16Char 加密后的字符串
 @return 加密后的字符串
 */
char *encodeBase16(const char *buf, const long size, const char *baseCharList, char *base16Char)
{
    
    const char *baseChars = baseCharList;
    
    if (NULL == baseChars) {
        baseChars = defaultBaseList;
    }
    
    
    int j = 0;//加密后字符循环
    int i = 0;//加密前字符循环
    
    while (i < size) {
        char ch = buf[i++];
        
        int int15 = 0x0F;//00001111
        
        base16Char[j++] = baseChars[ch >> 4 & int15];
        base16Char[j++] = baseChars[ch & int15];
    }
    
    base16Char[j] = '\0';
    
    return base16Char;
}


/**
 base16解密 （单调双返回）编码后的字符串，逐个取出字符，把字符对应base数组的下标找出来，两个一组，前一个作揖4位 或 上后一个，组成新的字符

 @param base16Char 加密后的base16字符串
 @param base16CharSize 加密后的字符串长度
 @param originChar 原始字符串
 @return 原始字符串
 */
char *decodeBase16(const char *base16Char, const long base16CharSize, const char *baseCharList, char *originChar) {
    
    if (NULL == base16Char || NULL == originChar) {
        return NULL;
    }
    
    const char *baseChars = baseCharList;
    
    if (NULL == baseChars) {
        baseChars = defaultBaseList;
    }
    
    long originCharSize = (strlen(base16Char) / 2) + 1;
    
    char char0 = 0;
    char char1 = 0;
    
    long i = 0;
    long j = 0;
    
    while (i < base16CharSize && j < originCharSize) {
        char0 = base16Char[i++];
        char1 = base16Char[i++];
        int int15 = 0x0F; //00001111
        int int240 = 0xF0;//00001111
        
        int b0Index;
        indexChar(baseChars, strlen(baseChars), char0, &b0Index);
        
        int b1Index;
        indexChar(baseChars, strlen(baseChars), char1, &b1Index);
        
        char newChar = ((b0Index << 4) & int240) | (b1Index & int15);
        
        originChar[j++] = newChar;
    }
    
    
    originChar[j] = '\0';
    
    return originChar;
}


static void indexChar(const char *buff, long buffSize, char ch, int *index)
{
    int i = 0;
    
    for (i = 0; i < buffSize; i++) {
        if (ch == buff[i]) {
            *index = i;
            break;
        }
    }
}
@end
